#include "texgen.h"

using namespace goatgfx;

static void intcolor(const Vector4 &color, int *icol);

Image *goatgfx::texgen_solid(int xsz, int ysz, const Vector4 &color)
{
	Image *img = new Image;
	if(!img->create(xsz, ysz, Image::FMT_RGBA)) {
		delete img;
		return 0;
	}

	int col[4];
	intcolor(color, col);

	unsigned char *pix = (unsigned char*)img->get_pixels();
	for(int i=0; i<xsz * ysz; i++) {
		*pix++ = col[0];
		*pix++ = col[1];
		*pix++ = col[2];
		*pix++ = col[3];
	}
	return img;
}

Image *goatgfx::texgen_chess(int xsz, int ysz, int usub, int vsub, const Vector4 &col1, const Vector4 &col2)
{
	Image *img = new Image;
	if(!img->create(xsz, ysz, Image::FMT_RGBA)) {
		delete img;
		return 0;
	}

	int c1[4], c2[4];
	intcolor(col1, c1);
	intcolor(col2, c2);

	int udiv = xsz / usub;
	int vdiv = ysz / vsub;

	unsigned char *pix = (unsigned char*)img->get_pixels();
	for(int i=0; i<ysz; i++) {
		for(int j=0; j<xsz; j++) {
			if(((i / vdiv) & 1) == ((j / udiv) & 1)) {
				*pix++ = c1[0];
				*pix++ = c1[1];
				*pix++ = c1[2];
				*pix++ = c1[3];
			} else {
				*pix++ = c2[0];
				*pix++ = c2[1];
				*pix++ = c2[2];
				*pix++ = c2[3];
			}
		}
	}
	return img;
}


Image *goatgfx::texgen(int xsz, int ysz, float usize, float vsize, Vector4 (*eval)(float, float, void*), void *cls)
{
	Image *img = new Image;
	if(!img->create(xsz, ysz, Image::FMT_RGBA)) {
		delete img;
		return 0;
	}

	unsigned char *pix = (unsigned char*)img->get_pixels();
	for(int i=0; i<ysz; i++) {
		for(int j=0; j<xsz; j++) {
			float x = usize * (float)j / (float)xsz;
			float y = vsize * (float)i / (float)ysz;

			Vector4 color = eval(x, y, cls);

			int icol[4];
			intcolor(color, icol);

			*pix++ = icol[0];
			*pix++ = icol[1];
			*pix++ = icol[2];
			*pix++ = icol[3];
		}
	}
	return img;
}


struct NoiseArg {
	int octaves;
	Vector4 col1, col2;
};

static Vector4 fbm_eval(float x, float y, void *cls)
{
	NoiseArg *arg = (NoiseArg*)cls;

	float noise = fbm2(x, y, arg->octaves) * 0.5 + 0.5;
	return lerp(arg->col1, arg->col2, noise);
}

static Vector4 fbm_abs_eval(float x, float y, void *cls)
{
	NoiseArg *arg = (NoiseArg*)cls;

	float noise = turbulence2(x, y, arg->octaves) * 0.5 + 0.5;
	return lerp(arg->col1, arg->col2, noise);
}


Image *goatgfx::texgen_fbm(int xsz, int ysz, float usize, float vsize, int octaves, const Vector4 &col1, const Vector4 &col2)
{
	NoiseArg arg = {octaves, col1, col2};
	if(arg.octaves < 1) {
		arg.octaves = 1;
	}

	return texgen(xsz, ysz, usize, vsize, fbm_eval, &arg);
}

Image *goatgfx::texgen_fbm_abs(int xsz, int ysz, float usize, float vsize, int octaves, const Vector4 &col1, const Vector4 &col2)
{
	NoiseArg arg = {octaves, col1, col2};
	if(arg.octaves < 1) {
		arg.octaves = 1;
	}

	return texgen(xsz, ysz, usize, vsize, fbm_abs_eval, &arg);
}

static inline void intcolor(const Vector4 &color, int *icol)
{
	for(int i=0; i<4; i++) {
		icol[i] = std::max(std::min((int)(color[i] * 255.0), 255), 0);
	}
}
